package gov.pbc.nn.uflo.view;

import gov.pbc.nn.core.dao.AbstractJdbcDao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.RowMapper;

import com.bstek.bdf2.core.context.ContextHolder;
import com.bstek.bdf2.core.orm.ParseResult;
import com.bstek.bdf2.uflo.proxy.model.ProxyDefinition;
import com.bstek.bdf2.uflo.proxy.service.ProxyService;
import com.bstek.dorado.annotation.DataProvider;
import com.bstek.dorado.annotation.Expose;
import com.bstek.dorado.data.entity.EntityUtils;
import com.bstek.dorado.data.provider.Criteria;
import com.bstek.dorado.data.provider.Page;
import com.bstek.uflo.model.HistoryTask;
import com.bstek.uflo.model.task.DateUnit;
import com.bstek.uflo.model.task.Task;
import com.bstek.uflo.model.task.TaskState;
import com.bstek.uflo.model.task.TaskType;
import com.bstek.uflo.service.HistoryService;
import com.bstek.uflo.service.ProcessService;
import com.bstek.uflo.service.TaskService;
import com.bstek.uflo.utils.EnvironmentUtils;

public class CopyOfPbcToDoTaskMaintain extends AbstractJdbcDao {
	@Autowired
	@Qualifier("uflo.taskService")
	private TaskService taskService;

	@Autowired
	@Qualifier("uflo.historyService")
	private HistoryService historyService;

	@Autowired
	@Qualifier("uflo.proxy.proxyService")
	private ProxyService proxyService;

	@Resource(name = ProcessService.BEAN_ID)
	private ProcessService processService;

	/**
	 * 加载待办任务
	 * 
	 * @param page
	 * @param criteria
	 */
	@DataProvider
	public void loadTodoTask(Page<Task> page, Criteria criteria) {
		String sql = "SELECT\n" + "	m.*\n" + "FROM\n" + "	(\n" + "		SELECT\n"
				+ "			t.*, p.NAME_ AS process_name_\n" + "		FROM\n"
				+ "			UFLO_TASK t\n"
				+ "		INNER JOIN uflo_process p ON t.PROCESS_ID_ = p.ID_\n"
				+ "		WHERE\n" + "			t.ASSIGNEE_ =?\n" + "	) m\n" + "WHERE\n"
				+ "	1 = 1 ";
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("assignee", ContextHolder.getLoginUserName());
		ParseResult result = this.parseCriteria(criteria, false, "m");
		if (result != null) {
			StringBuffer sb = result.getAssemblySql();
			Map<String, Object> valueMap = result.getValueMap();
			params.putAll(valueMap);
			sql += sb.toString();
		}
		this.pagingQuery(page, sql, params.values().toArray(),
				new TaskRowMapper());

	}

	/**
	 * 待领取任务
	 * 
	 * @param page
	 * @param criteria
	 */
	@DataProvider
	public void loadParticipatingTask(Page<Task> page, Criteria criteria) {
		String sql = "SELECT\n"
				+ "	m.*\n"
				+ "FROM\n"
				+ "	(\n"
				+ "		SELECT\n"
				+ "			t.*, p.NAME_ AS process_name_\n"
				+ "		FROM\n"
				+ "			UFLO_TASK t\n"
				+ "		INNER JOIN uflo_process p ON t.PROCESS_ID_ = p.ID_\n"
				+ "		INNER JOIN UFLO_TASK_PARTICIPATOR tp ON t.ID_ = tp.TASK_ID_\n"
				+ "		WHERE\n" + "			t.STATE_ =?\n" + "		AND (tp.USER_ =?)\n"
				+ "	) m\n" + "WHERE\n" + "	1 = 1";
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("state", TaskState.Ready);
		params.put("assignee", ContextHolder.getLoginUserName());
		ParseResult result = this.parseCriteria(criteria, false, "m");
		if (result != null) {
			StringBuffer sb = result.getAssemblySql();
			Map<String, Object> valueMap = result.getValueMap();
			params.putAll(valueMap);
			sql += sb.toString();
		}
		this.pagingQuery(page, sql, params.values().toArray(),
				new TaskRowMapper());
	}

	/**
	 * 过期任务
	 * 
	 * @param page
	 * @param criteria
	 */
	@DataProvider
	public void loadExpiredTask(Page<Task> page, Criteria criteria) {
		String sql = "SELECT\n" + "	m.*\n" + "FROM\n" + "	(\n" + "		SELECT\n"
				+ "			t.*, p.NAME_ AS process_name_\n" + "		FROM\n"
				+ "			UFLO_TASK t\n"
				+ "		INNER JOIN uflo_process p ON t.PROCESS_ID_ = p.ID_\n"
				+ "		WHERE\n" + "			t.ASSIGNEE_ =?\n" + "		AND t.DUEDATE_ <?\n"
				+ "	) m\n" + "WHERE\n" + "	1 = 1";
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("assignee", ContextHolder.getLoginUserName());
		params.put("dueDate", new Date());
		ParseResult result = this.parseCriteria(criteria, false, "m");
		if (result != null) {
			StringBuffer sb = result.getAssemblySql();
			Map<String, Object> valueMap = result.getValueMap();
			params.putAll(valueMap);
			sql += sb.toString();
		}
		this.pagingQuery(page, sql, params.values().toArray(),
				new TaskRowMapper());
	}

	/**
	 * 我处理的任务
	 * 
	 * @param page
	 * @param criteria
	 */
	@DataProvider
	public void loadHistoryTask(Page<HistoryTask> page, Criteria criteria) {
		String sql = "SELECT\n" + "	m.*\n" + "FROM\n" + "	(\n" + "		SELECT\n"
				+ "			t.*, p.NAME_ AS process_name_\n" + "		FROM\n"
				+ "			UFLO_HIS_TASK t\n"
				+ "		INNER JOIN uflo_process p ON t.PROCESS_ID_ = p.ID_\n"
				+ "		WHERE\n" + "			this_.ASSIGNEE_ =?\n" + "	) m\n"
				+ "WHERE\n" + "	1 = 1";

		Map<String, Object> params = new HashMap<String, Object>();
		params.put("assignee", ContextHolder.getLoginUserName());
		ParseResult result = this.parseCriteria(criteria, false, "m");
		if (result != null) {
			StringBuffer sb = result.getAssemblySql();
			Map<String, Object> valueMap = result.getValueMap();
			params.putAll(valueMap);
			sql += sb.toString();
		}
		this.pagingQuery(page, sql, params.values().toArray(),
				new HisTaskRowMapper());
	}

	/**
	 * 获取代理的待办任务
	 * 
	 * @param page
	 * @param criteria
	 * @param params
	 */
	@DataProvider
	public void loadProxyTodoTasks(Page<Task> page, Criteria criteria,
			Map<String, Object> params) {
		String issueUser = (String) params.get("issueUser");
		Date start = (Date) params.get("start");
		Date end = (Date) params.get("end");
		boolean isProxyAll = ((Boolean) params.get("isProxyAll"))
				.booleanValue();
		String proxyDefId = params.get("proxyDefId").toString();

		List<Object> ps = new ArrayList<Object>();
		ps.add(issueUser);
		ps.add(start);
		ps.add(end);
		List<Long> proxyDefList = Collections.emptyList();
		if (!isProxyAll) {
			proxyDefList = this.proxyService.findProxyProcessList(proxyDefId);
			if (proxyDefList != null && !proxyDefList.isEmpty())
				ps.add(proxyDefList);
		}
		if ((proxyDefList.size() > 0) || (isProxyAll)) {
			String sql = "SELECT\n" + "	m.*\n" + "FROM\n" + "	(\n"
					+ "		SELECT\n" + "			t.*, p.NAME_ AS process_name_\n"
					+ "		FROM\n" + "			uflo_task t\n"
					+ "		INNER JOIN uflo_process p ON t.PROCESS_ID_ = p.ID_\n"
					+ "		WHERE\n" + "			t.ASSIGNEE_ =?\n"
					+ "		AND t.CREATE_DATE_ >=?\n"
					+ "		AND t.CREATE_DATE_ <=?\n" + "	) m\n" + "WHERE\n"
					+ "	1 = 1";

			ParseResult result = this.parseCriteria(criteria, false, "m");
			if (result != null) {
				StringBuffer sb = result.getAssemblySql();
				Map<String, Object> valueMap = result.getValueMap();
				ps.addAll(valueMap.values());
				sql += sb.toString();
			}
			this.pagingQuery(page, sql, ps.toArray(), new TaskRowMapper());
		}
	}

	/**
	 * 获取代理的待领取的任务
	 * 
	 * @param page
	 * @param criteria
	 * @param params
	 */
	@DataProvider
	public void loadProxyPartiTasks(Page<Task> page, Criteria criteria,
			Map<String, Object> params) {
		String issueUser = (String) params.get("issueUser");
		Date start = (Date) params.get("start");
		Date end = (Date) params.get("end");
		boolean isProxyAll = ((Boolean) params.get("isProxyAll"))
				.booleanValue();
		String proxyDefId = params.get("proxyDefId").toString();

		List<Object> ps = new ArrayList<Object>();
		ps.add(issueUser);
		ps.add(TaskState.Ready);
		ps.add(start);
		ps.add(end);
		List<Long> proxyDefList = Collections.emptyList();
		if (!isProxyAll) {
			proxyDefList = this.proxyService.findProxyProcessList(proxyDefId);
			if (proxyDefList != null && !proxyDefList.isEmpty())
				ps.add(proxyDefList);
		}
		if ((proxyDefList.size() > 0) || (isProxyAll)) {
			String sql = "SELECT\n"
					+ "	m.*\n"
					+ "FROM\n"
					+ "	(\n"
					+ "		SELECT\n"
					+ "			t.*, p.NAME_ AS process_name_\n"
					+ "		FROM\n"
					+ "			uflo_task t\n"
					+ "		INNER JOIN uflo_process p ON t.PROCESS_ID_ = p.ID_\n"
					+ "		INNER JOIN UFLO_TASK_PARTICIPATOR tp ON t.ID_ = tp.TASK_ID_\n"
					+ "		WHERE\n" + "			tp.USER_ =?\n" + "		AND t.STATE_ =?\n"
					+ "		AND t.CREATE_DATE_ >=?\n"
					+ "		AND t.CREATE_DATE_ <=?\n" + "	) m\n" + "WHERE\n"
					+ "	1 = 1";

			ParseResult result = this.parseCriteria(criteria, false, "m");
			if (result != null) {
				StringBuffer sb = result.getAssemblySql();
				Map<String, Object> valueMap = result.getValueMap();
				ps.addAll(valueMap.values());
				sql += sb.toString();
			}
			this.pagingQuery(page, sql, ps.toArray(), new TaskRowMapper());
		}
	}

	/**
	 * 获取代理定义
	 * 
	 * @return
	 */
	@DataProvider
	public List<ProxyDefinition> loadProxyDefinitions() {
		return this.proxyService.findProxyDefinitions(EnvironmentUtils
				.getEnvironment().getLoginUser());
	}

	@Expose
	public void complete(Task task) {
		this.taskService.start(task.getId());
		this.taskService.complete(task.getId());
	}

	@Expose
	public void proxyClaimTask(long taskId, String user) {
		this.taskService.claim(taskId, user);
	}

	public static class TaskRowMapper implements RowMapper<Task> {

		@Override
		public Task mapRow(ResultSet rs, int rowNum) throws SQLException {
			Task task = new Task();
			task.setId(rs.getLong("ID_"));
			task.setAssignee(rs.getString("ASSIGNEE_"));
			task.setBusinessId(rs.getString("BUSINESS_ID_"));
			task.setCountersignCount(rs.getInt("COUNTERSIGN_COUNT_"));
			task.setCreateDate(rs.getDate("CREATE_DATE_"));
			task.setDateUnit(DateUnit.valueOf(rs.getString("DATE_UNIT_")));
			task.setDescription(rs.getString("DESCRIPTION_"));
			task.setDueActionDate(rs.getDate("DUE_ACTION_DATE_"));
			task.setDuedate(rs.getDate("DUEDATE_"));
			task.setNodeName(rs.getString("NODE_NAME_"));
			task.setOpinion(rs.getString("OPINION_"));
			task.setOwner(rs.getString("OWNER_"));
			task.setPrevState(TaskState.valueOf(rs.getString("PREV_STATE_")));
			task.setPrevTask(rs.getString("PREV_TASK_"));
			task.setProcessId(rs.getLong("PROCESS_ID_"));
			task.setProcessInstanceId(rs.getLong("PROCESS_INSTANCE_ID_"));
			task.setProgress(rs.getInt("PROGRESS_"));
			task.setRootProcessInstanceId(rs
					.getLong("ROOT_PROCESS_INSTANCE_ID_"));
			task.setState(TaskState.valueOf(rs.getString("STATE_")));
			task.setTaskName(rs.getString("TASK_NAME_"));
			task.setType(TaskType.valueOf(rs.getString("TYPE_")));
			task.setUrl(rs.getString("URL_"));
			try {
				task = EntityUtils.toEntity(task);
				EntityUtils.setValue(task, "processName",
						rs.getString("process_name_"));
			} catch (Exception e) {
				e.printStackTrace();
			}
			return task;
		}

	}

	public static class HisTaskRowMapper implements RowMapper<HistoryTask> {

		@Override
		public HistoryTask mapRow(ResultSet rs, int rowNum) throws SQLException {
			HistoryTask task = new HistoryTask();
			task.setId(rs.getLong("ID_"));
			task.setAssignee(rs.getString("ASSIGNEE_"));
			task.setBusinessId(rs.getString("BUSINESS_ID_"));
			task.setCreateDate(rs.getDate("CREATE_DATE_"));
			task.setDescription(rs.getString("DESCRIPTION_"));
			task.setDuedate(rs.getDate("DUEDATE_"));
			task.setNodeName(rs.getString("NODE_NAME_"));
			task.setOpinion(rs.getString("OPINION_"));
			task.setOwner(rs.getString("OWNER_"));
			task.setProcessId(rs.getLong("PROCESS_ID_"));
			task.setProcessInstanceId(rs.getLong("PROCESS_INSTANCE_ID_"));
			task.setRootProcessInstanceId(rs
					.getLong("ROOT_PROCESS_INSTANCE_ID_"));
			task.setState(TaskState.valueOf(rs.getString("STATE_")));
			task.setTaskName(rs.getString("TASK_NAME_"));
			task.setType(TaskType.valueOf(rs.getString("TYPE_")));
			task.setUrl(rs.getString("URL_"));
			try {
				task = EntityUtils.toEntity(task);
				EntityUtils.setValue(task, "processName",
						rs.getString("process_name_"));
			} catch (Exception e) {
				e.printStackTrace();
			}
			return task;
		}

	}
}
